/*
 
 A Simple test of a RTS game implementation

*/

// The game
#include "GameImplementation.h"
#include "TechBattleControl.h"
#include "UnitTypes.h"

// Putin Engine, should really be something like #include Putin.h
#include "../gfx/RenderEngine.h"
#include "../engine/BattleControl.h"
#include "../engine/EngineController.h"
#include "../engine/Player.h"
#include "../shared/Time.h"
#include "../engine/input.h"
#include "../engine/Map.h"
#include "../shared/utils.h"
#include "../engine/Gamestate.h"
#include "../utils/Profiler.h"
#include "../shared/Logger.h"
#include "../multimedia/SoundManager/SoundManager/include/SoundManager.h"
#include "../multimedia/SoundManager/SoundManager/include/ExplosionReverbFilter.h"

#define WIN32_LEAN_AND_MEAN
#define DEBUG

// System Includes
#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <cstdlib> // for random number generation

Vec3f tempSpeed = Vec3f(1.0f,1.0f,1.0f);
SFXFilter* filter = NULL;

//Leo2a5* target = NULL;
//LeoArcher* shooter = NULL;


/*!
 * \brief
 * Game logic frame listener.
 * Executes once a frame.
 * With small nice functions that can be
 * usefull for checking things.
 * Testing etc.
 */
class TestEvent : public Putin::UpdateEvent
{
public:

	void frameEvent(BattleControl* bc)
	{
		updateBullets(bc);
	}

	void updateBullets(BattleControl* bc)
	{
		// Ugly hack to spawn bullets and remove them. feel free to move this, not sure where it should be
		double currentTime = Time::instance().getTotalTime();

		for each(std::pair<int,Unit*> up in bc->getState()->mUnits)
		{
			Unit* unit = up.second;
			
			if(unit->getIsShooting())
			{
				TechTank* t = (TechTank*)unit;
				if( t->mHP <= 0 ) // Cannot fire while dead!! :)
					continue;
				// cooled down enough to fire again
				if(currentTime > unit->getLastShot() + unit->getShootingCooldown())
				{
					//Bullet* m = new RegularBullet(unit->getPosition(), unit->getShootingTarget(),unit->getID());
					bc->spawnBullet(t->createBullet());
				//	unit->addChildEffect("Putin/TankMuzzleFire");
					RenderEngine::instance().addParticleEffect( Putin::Utils::intToString( unit->getID()),
																t->getMuzzleEffect(),true);
					unit->setLastShot(currentTime);

					// play sound of tank canon						
					bc->playSound("tank_canon.wav", t->getPosition(), tempSpeed, "normal");
				}
				//BattleControl::instance().spawnBullet();
				
				//Bullet* m = new MissileX(shooter->getPosition(), target->getPosition(),1);
				//bc->spawnBullet(m);
			}
		}

		// Check hit targets and add some visual effects to them
		std::list<Bullet*> toRemove;
		for each( std::pair<int,Putin::Bullet*> bp in bc->getBullets() )
		{
			TechBullet* b = (TechBullet*)bp.second;
			if( b->mHasExploded )
			{
				for each( int uid in b->mUnitsHit )
				{
					TechTank* uHit = (TechTank*)bc->getState()->getUnit(uid);
					uHit->mHP -= b->mDamage;
					if(uHit->mHP >= 0)
					{
						if( uHit->mHP <= 3 )
						{
							RenderEngine::instance().addParticleEffect( Putin::Utils::intToString( uHit->getID()),
																	"Putin/TankFire",true);
						} else if( uHit->mHP <=6 ) {
								
								RenderEngine::instance().addParticleEffect( Putin::Utils::intToString( uHit->getID()),
																	"Putin/TankSmoke",true);
						}
					}

					// play sound of tank getting hit
					string sound = "tank_hit_1.wav";
					int randInt = rand();
					if (randInt < (RAND_MAX / 2))
						sound = "tank_hit_2.wav";
						
					bc->playSound(sound, uHit->getPosition(), tempSpeed, "loud");
					if (SoundManager::instancePtr()->distanceToListener(NULL, uHit->getPosition().v, "bullet hit") < 200)
						SoundManager::instancePtr()->enableSoundsSFXFilter(filter, 3);
				}
				toRemove.push_back(b);
				b->mHasExploded = false; // DEBUG. set to avoid repeated hits.
			}
		}

		for each(Bullet* b in toRemove)
		{
		//	bc->removeBullet(b);
		}
	}
};



//----------------------------------
// TechDemo class Functions
void TechDemo::start()
{
	Putin::Profiler* pppp = new Putin::Profiler();
	Putin::EngineController* ec = new Putin::EngineController();

	ec->init();

	filter = new ExplosionReverbFilter;

	bool multiplay = false;

	BattleControl* bc = new TechBattleControl(multiplay);
	ec->preloadState(bc);
	ec->changeState();

	if( !multiplay ) // then just do some offline testing
	{
		Player * p1 = new Player("Player1");
		bc->getState()->add(p1);

		Player * p2 = new Player("Player2");
		bc->getState()->add(p2);

		// Keep this included and place funny game code in it. 
		// Such as game logic, semi-ai and stuff.

		for(int i=0;i<16;i++)
		{
			bc->spawnUnit(new Leo(Vec3f(175.0f,130.0f,55)+Formation::offset(i),Vec3f(1.0f,0.0f,0.0f),p1));
		}

		for(int i=0;i<6;i++)
		{
			bc->spawnUnit(new Truck(Vec3f(50.0f,130.0f,55)+Formation::offset(i),Vec3f(1.0f,0.0f,0.0f),p1));
		}

		for(int i=1;i<7;i++)
		{
			bc->spawnUnit(new RedArcher(Vec3f(375.0f,i*30.0f,55),Vec3f(1.0f,0.0f,0.0f),p2));
		}

		for(int i=1;i<7;i++)
		{
			bc->spawnUnit(new RedTruck(Vec3f(400.0f,i*30.0f,55),Vec3f(1.0f,0.0f,0.0f),p2));
		}

		bc->mUpdateEvent = new TestEvent();

		RenderEngine::instance().setTextOverlay( "Arrows, pgup-down, mouse right-left" );
		
	}
	RenderEngine::instance().showTextOverlay( true );
	ec->start();

	Putin::Logger::instance().logg( Putin::Profiler::instance().getReport() );
	delete bc;
	delete ec;
}